#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include "main.h"


#include "WorldStatusUpdate.pb.h"
#include "Commands.pb.h"
#include "ProtobufUtil.hh"

using namespace strategy_protocol;
using namespace protoutil;
using namespace std;

void TheStrategy::synchronized_moving()
{
	workers_synchronized_moving();
	soldiers_synchronized_moving();
}

void TheStrategy::best_routes_to_mines()
{
	cerr << "Computing best routes to mines ... ";
	forward_route.resize(mines.size());
	backward_route.resize(mines.size());
	for(int j=0;j<mines.size();j++)
	{
		vector<Position> empty_route;
		forward_route[j]=route(base_pos,mines[j].common().position(),empty_route);
		backward_route[j]=route(mines[j].common().position(),forward_route[j][0],forward_route[j]);
		forward_route[j].push_back(mines[j].common().position());
		backward_route[j].push_back(forward_route[j][0]);
	}
	cerr << "DONE";

}

void TheStrategy::workers_on_the_best_routes()
{
	for(int i=0;i<world.workers_size();i++)
	{
		int hismine=-1;
		Position target_pos;
		for(int j=0;j<mines.size();j++)
			if(same_pos(mines[j].common().position(),his_mine[world.workers(i).common().id()])) hismine=j;

        if(hismine!=-1)
        {
            target_pos=workers_task[world.workers(i).common().id()].target_pos;

            if(same_pos(world.workers(i).common().position(),base_pos))
                    target_pos = forward_route[hismine][0];

            if(same_pos(workers_task[world.workers(i).common().id()].target_pos,world.workers(i).common().position()))
            {
                if(same_pos(world.workers(i).common().position(),mines[hismine].common().position()))
                    target_pos = backward_route[hismine][0];
                else
                {
                    for(unsigned int k=0;k<forward_route[hismine].size()-1;k++)
                        if(same_pos(world.workers(i).common().position(),forward_route[hismine][k]))
                            target_pos=forward_route[hismine][k+1];
                    for(unsigned int k=0;k<backward_route[hismine].size()-1;k++)
                        if(same_pos(world.workers(i).common().position(),backward_route[hismine][k]))
                        target_pos=backward_route[hismine][k+1];
                }
            }

            workers_task[world.workers(i).common().id()].target_pos = target_pos;
            workers_task[world.workers(i).common().id()].approx=false;
        }
	}
}

void TheStrategy::workers_synchronized_moving()
{
	vector<bool> has_moved;
	has_moved.resize(world.workers_size(),false);
	bool everybody_moved=false;

	while(!everybody_moved)
	{
		everybody_moved=true;
		for(int i=0;i<world.workers_size();i++)
		{
			if(!has_moved[i])
			{
				Position target_pos = workers_task[world.workers(i).common().id()].target_pos;
				Position next_pos = nextstep(world.workers(i).common().position(),target_pos,
											workers_task[world.workers(i).common().id()].approx,false);
				if(mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]==' ' || mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]=='M')
				{
					has_moved[i]=true;
					movecmd(world.workers(i),next_pos);
					everybody_moved=false;
				}
			}
		}
	}

	everybody_moved=false;
	while(!everybody_moved)
	{
		everybody_moved=true;
		for(int i=0;i<world.workers_size();i++)
		{
			if(!has_moved[i])
			{
				Position target_pos = workers_task[world.workers(i).common().id()].target_pos;
				Position next_pos = nextstep(world.workers(i).common().position(),target_pos,
											workers_task[world.workers(i).common().id()].approx,true);
				if(mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]==' ' || mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]=='M')
				{
					has_moved[i]=true;
					movecmd(world.workers(i),next_pos);
					everybody_moved=false;
				}
			}
		}
	}

	for(int i=0;i<world.workers_size();i++)
	{
		if(has_moved[i])
			workers_task[world.workers(i).common().id()].waiting = 0;
		else
			workers_task[world.workers(i).common().id()].waiting++;
	}
	bool goaway=false;
	for(int i=0;i<world.workers_size() && !goaway;i++)
		if(workers_task[world.workers(i).common().id()].waiting>2 &&
			!same_pos(world.workers(i).common().position(),nextstep(world.workers(i).common().position(),base_pos,true,true)))
		{
			what_should_i_do(world.workers(i),true);
			need_worker=false;
			goaway=true;
		}
}

void TheStrategy::soldiers_synchronized_moving()
{
	vector<bool> has_moved;
	has_moved.resize(world.soldiers_size(),false);
	bool everybody_moved=false;

	while(!everybody_moved)
	{
		everybody_moved=true;
		for(int i=0;i<world.soldiers_size();i++)
		{
			if(!has_moved[i] && soldiers_task[world.soldiers(i).common().id()].task==MOVE)
			{
				Position target_pos = soldiers_task[world.soldiers(i).common().id()].target_pos;
				Position next_pos = nextstep(world.soldiers(i).common().position(),target_pos,
											soldiers_task[world.soldiers(i).common().id()].approx,false);
				if(mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]==' ' || mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]=='M')
				{
					has_moved[i]=true;
					movecmd(world.soldiers(i),next_pos);
					everybody_moved=false;
				}
			}
		}
	}

	everybody_moved=false;
	while(!everybody_moved)
	{
		everybody_moved=true;
		for(int i=0;i<world.soldiers_size();i++)
		{
			if(!has_moved[i] && soldiers_task[world.soldiers(i).common().id()].task==MOVE)
			{
				Position target_pos = soldiers_task[world.soldiers(i).common().id()].target_pos;
				Position next_pos = nextstep(world.soldiers(i).common().position(),target_pos,
											soldiers_task[world.soldiers(i).common().id()].approx,true);
				if(mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]==' ' || mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]=='M')
				{
					has_moved[i]=true;
					movecmd(world.soldiers(i),next_pos);
					everybody_moved=false;
				}
			}
		}
	}

	everybody_moved=false;
	while(!everybody_moved)
	{
		everybody_moved=true;
		for(int i=0;i<world.soldiers_size();i++)
		{
			if(!has_moved[i] && soldiers_task[world.soldiers(i).common().id()].task==MOVE &&
				!same_pos(soldiers_task[world.soldiers(i).common().id()].target_pos,world.soldiers(i).common().position()))
			{
				Position target_pos = boss_pos;
				Position next_pos = nextstep(world.soldiers(i).common().position(),target_pos,
											soldiers_task[world.soldiers(i).common().id()].approx,true);
				if(mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]==' ' || mymap[next_pos.x()-translation_x][next_pos.y()-translation_y]=='M')
				{
					has_moved[i]=true;
					movecmd(world.soldiers(i),next_pos);
					everybody_moved=false;
				}
			}
		}
	}

	for(int i=0;i<world.soldiers_size();i++)
	{
		if(boss_found && !has_moved[i])
			attackcmd(world.soldiers(i),boss_id);
	}
}
